package top.yfq.multidatasource.config;

import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.support.TransactionTemplate;
import top.yfq.multidatasource.datasource.DataSourceInfo;
import top.yfq.multidatasource.datasource.DynamicDataSource;
import top.yfq.multidatasource.datasource.IDataSourceService;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * @author yfq
 * @date 2025/9/26 22:31
 * @description 动态数据源配置
 */
@Configuration
public class DynamicDataSourceConfig {

    // 主库（租户注册、元数据等）
    @ConfigurationProperties("spring.datasource.master")
    @Bean
    public DataSource masterDataSource() {
        return DataSourceBuilder.create().build();
    }

    // 用户来加载租户信息
    @Bean
    @Primary
    public JdbcTemplate jdbcTemplate(DataSource masterDataSource) {
        JdbcTemplate jdbcTemplate = new JdbcTemplate(masterDataSource);
        jdbcTemplate.setFetchSize(100);
        jdbcTemplate.setMaxRows(1000);
        jdbcTemplate.setQueryTimeout(60);

        return jdbcTemplate;
    }

    @Bean
    public DataSource dynamicDataSource(IDataSourceService dataSourceService) {
        DynamicDataSource dynamicDataSource = new DynamicDataSource(dataSourceService);

        // 1. 设置默认数据源为主库
        dynamicDataSource.setDefaultTargetDataSource(masterDataSource());

        // 2. 获取所有租户的数据源
        dynamicDataSource.setTargetDataSources(loadDataSources(dataSourceService));

        return dynamicDataSource;
    }

    public Map<Object, Object> loadDataSources(IDataSourceService dataSourceService) {
        // 从配置文件加载租户（适合租户较少）
//        loadTenantDataSourcesFromConfig(targetDataSources);

        dataSourceService.init();

        Map<Object, Object> targetDataSources = new HashMap<>();
        for (DataSourceInfo dataSourceInfo : dataSourceService.dataSourcesInfos()) {
            HikariDataSource ds = new HikariDataSource();
            ds.setJdbcUrl(dataSourceInfo.getJdbcUrl());
            ds.setUsername(dataSourceInfo.getUsername());
            ds.setPassword(dataSourceInfo.getPassword());
            ds.setPoolName("Tenant-" + dataSourceInfo.getKey() + "-Pool");
            targetDataSources.put(dataSourceInfo.getKey(), ds);
        }

        return targetDataSources;
    }

    @Bean
    @Primary
    public SqlSessionFactory sqlSessionFactory(DataSource dynamicDataSource) throws Exception {
        // 将配置映射到配置类
//        MybatisScannerProperties mybatisScannerProperties = PropertyUtil.convertToTarget(environment, Constants.MybatisScannerConstants.PREFIX, MybatisScannerProperties.class);

        // 配置mybatis-plus扫描
        MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();

        // 指定数据源为配置的动态数据源
        factory.setDataSource(dynamicDataSource);
        factory.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources("classpath*:/mapper/*.xml"));
//        factory.setTypeAliasesPackage(mybatisScannerProperties.getTypeAliasesPackage());

        MybatisConfiguration configuration = new MybatisConfiguration();

        // 开启数据库字段下划线命名到Java属性驼峰命名的自动映射
        configuration.setMapUnderscoreToCamelCase(true);

        // 日志输出类配置
//        configuration.setLogImpl((Class<? extends Log>) Class.forName(mybatisScannerProperties.getLogImpl()));

        factory.setConfiguration(configuration);
        return factory.getObject();
    }

    @Bean
    @Primary
    public DataSourceTransactionManager transactionManager(DataSource dynamicDataSource) {
        return new DataSourceTransactionManager(dynamicDataSource);
    }

    @Bean
    public TransactionTemplate transactionTemplate(DataSourceTransactionManager transactionManager) {
        TransactionTemplate transactionTemplate = new TransactionTemplate();
        transactionTemplate.setTransactionManager(transactionManager);
        transactionTemplate.setPropagationBehaviorName("PROPAGATION_REQUIRED");
        return transactionTemplate;
    }

//    private void loadTenantDataSourcesFromConfig(Map<Object, Object> targetDataSources) {
//        // 示例：从 classpath:tenants/*.yml 加载租户配置
//        Resource[] resources;
//        try {
//            resources = new PathMatchingResourcePatternResolver()
//                    .getResources("classpath:tenants/*.yml");
//        } catch (IOException e) {
//            throw new RuntimeException("无法加载租户配置", e);
//        }
//
//        Yaml yaml = new Yaml();
//        for (Resource resource : resources) {
//            try (InputStream is = resource.getInputStream()) {
//                Map<String, Object> config = yaml.load(is);
//                String tenantId = String.valueOf(config.get("tenantId"));
//                String url = (String) config.get("url");
//                String username = (String) config.get("username");
//                String password = (String) config.get("password");
//
//                HikariDataSource ds = new HikariDataSource();
//                ds.setJdbcUrl(url);
//                ds.setUsername(username);
//                ds.setPassword(password);
//                ds.setPoolName("Tenant-" + tenantId + "-Pool");
//
//                targetDataSources.put(tenantId, ds);
//            } catch (IOException e) {
//                throw new RuntimeException("加载租户配置失败: " + resource.getFilename(), e);
//            }
//        }
//    }
}
